# -*- coding:utf-8 -*-
import os,sys
import re
import traceback
import time
from collections import deque
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), os.pardir, os.pardir))
import supeanut_config
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), os.pardir))
from CommonLib.mylog import mylog
from ExrightsTool import ExrightsTool
from TecIndexRecog import TecIndexRecog

'''
作者：supeanut
创建时间：2016-xx-xx xx:xx:xx
功能描述：
	趋势识别、股价位置识别、成交量趋势识别等等
相关配置：
	supeanut_config.XXX
历史改动：
	2016-xx-xx: xxxxxx
'''
class TrendRecog:
	def __init__(self):
		pass

	def getParamRange(self, func_name):
		if func_name == "pingTai":
			return {"item_len":[[10,20],10],"volat":[[0.10,0.20],0.05]}
		if func_name == "pricePos":
			return {"historyAll":[[0,1],1],"item_len":[[10,30],10],\
					"posPercentMin":[[0.05,0.1],0.05],"posPercentMax":[[0.15,0.2],0.05]}
		if func_name == "warmUpShoot":
			return {"warmDays":[[2,10],1],"ma_days":[[20,20],1],"KlenMin":[[0.07,0.1],0.01],\
					"volSurpass":[[0.3,0.5],0.1],"maDiff":[[0.01,0.02],0.01],"StartMaPos":[[0.1,0.5],0.1]}
		if func_name == "priceVolMaUp":
			return {"subItem":[[1,5],1],"ma_days":[[10,20],10]}
		if func_name == "priceVolCoor":
			return {"item_len":[[5,5],1],"vol_ma_days":[[5,5],1],"indexMin":[[0.10,0.10],0.1],"indexMax":[[9.9,9.9],0.1]}
		if func_name == "redGreenRatio":
			return {"item_len":[[20,20],1],"ratioMin":[[0.6,0.6],0.1],"ratioMax":[[1.0,1.0],0.1]}
		if func_name == "KDJGoldCross":
			return {"KDpos":[[0.5,0.5],0.1],"periodN":[[9,9],1],"KsmaN":[[3,3],1],"DsmaN":[[3,3],1]}
		if func_name == "ma3duoTouPaiLie":
			return {"ma1":[[5,5],1],"ma2":[[10,10],1],"ma3":[[20,20],1]}
		if func_name == "RedAndVolBig":
			return {"redLenth":[[0.03,0.03],0.01],"volma1":[[5,5],1],"volma2":[[10,10],1],"greenDays":[[3,3],1]}

	# item_len:平台周期数，volat:波动限制
	# period: 在itemList数据范围内，另外指定更小的范围，为了解决类似MA610，历史位置的不稳定问题
	def pingTai(self, itemList, item_len=10, volat=0.15, period=[None,None]):
		if len(itemList) < item_len:
			return True, []
		period_start = itemList[0][0] if period[0] is None else period[0]
		period_end = itemList[-1][0] if period[1] is None else period[1]
		print period_start, period_end
		# 初始化待识别的items组
		temp_highs = deque([])
		temp_lows = deque([])
		temp_items_date = ""
		for i in range(0, item_len-1):
			temp_highs.append(itemList[i][3])
			temp_lows.append(itemList[i][4])
		temp_high = max(temp_highs)
		temp_low = min(temp_lows)
		# 全量识别
		result_list = []
		for item in itemList[item_len-1:]:
			temp_items_date = item[0]
			# 鉴别period区间
			if temp_items_date < period_start or temp_items_date > period_end:
				continue
			temp_highs.append(item[3])
			temp_lows.append(item[4])
			# 识别算法
			reg_tag = True
			if temp_high < item[3]:
				temp_high = item[3]
			if temp_low > item[4]:
				temp_low = item[4]
			temp_volat = abs((temp_high - temp_low) / temp_low)
			if temp_volat > volat:
				reg_tag = False
			# 识别结果
			if reg_tag is True:
				result_list.append(temp_items_date)
			pop_high = temp_highs.popleft()
			pop_low = temp_lows.popleft()
			if pop_high == temp_high:
				temp_high = max(temp_highs)
			if pop_low == temp_low:
				temp_low = min(temp_lows)
		return result_list

	# 收盘价在历史区域内的高度
	# item_len = None时，取上市到现在的时间区间;取整数时，忽略前期小于整数个的周期
	# posPercent闭闭区间
	def pricePos(self, itemList, historyAll=1, item_len=10, posPercentMin=0.0, posPercentMax=0.4, period=[None,None]):
		result_list = []
		temp_high = -99.99
		temp_low = 9999999.99
		# 历史价格高度
		if historyAll == 1:
			for item in itemList:
				item_high = item[3]
				item_low = item[4]
				if temp_high < item_high:
					temp_high = item_high
				if temp_low > item_low:
					temp_low = item_low
				if (temp_high - temp_low) == 0.0:
					curPos = 1.0
				else:
					curPos = (item[2] - temp_low) / (temp_high - temp_low)
				if curPos >= posPercentMin and curPos <= posPercentMax:
					result_list.append(item[0])
			return result_list
		# 区间价格高度
		if len(itemList) < item_len:
			return []
		period_start = itemList[0][0] if period[0] is None else period[0]
		period_end = itemList[-1][0] if period[1] is None else period[1]
		temp_highs = deque([i[3] for i in itemList[:item_len-1]])
		temp_lows = deque([i[4] for i in itemList[:item_len-1]])
		for item in itemList[item_len-1:]:
			if temp_items_date < period_start or temp_items_date > period_end:
				continue
			temp_highs.append(item[3])
			temp_lows.append(item[4])
			# 计算最大最小还可优化
			temp_high = max(temp_highs)
			temp_low = min(temp_lows)
			curPos = (item[2] - temp_low)/(temp_high - temp_low)
			if curPos >= posPercentMin and curPos <= posPercentMax:
				result_list.append(item[0])
			temp_highs.popleft()
			temp_lows.popleft()
		return result_list

	# 预热射击
	# 放量(10日均量线)长阳而后第一次回落20均线附近
	# warmDays:几日内(带起始长阳)出现过长阳，ma_days：回落几日均线，Klen：长阳长度，volSurpass：超过10日均量线百分比
	# maDiff:回落至ma均线的maDiff附近，StartMaPos：起始ma在起始长阳实体的高度位置之下(0.5表示ma在实体中间以下)
	def warmUpShoot(self, itemList, warmDays=10, ma_days=20, KlenMin=0.08, volSurpass=0.3, maDiff=0.01, StartMaPos=0.5, period=[None,None]):
		TecIndexObj = TecIndexRecog()
		ma_list = TecIndexObj.MA(itemList, 2, ma_days)
		volma_list = TecIndexObj.MA(itemList, 5, 10)
		# 找出放量长阳index
		index_list = []
		itemLen = len(itemList)
		for index in range(0,itemLen):
			item = itemList[index]
			closePrice = item[2]
			openPrice = item[1]
			# 去除前复权有可能导致的负价格
			if openPrice <= 0.0 or closePrice <= 0.0:
				continue
			# 挑选长阳
			Klen = (closePrice - openPrice) / openPrice
			if Klen < KlenMin:
				continue
			# 挑选放量
			vol = item[5]
			volma = volma_list[index]
			if (vol - volma)/volma < volSurpass:
				continue
			index_list.append(index)
		period_start = itemList[0][0] if period[0] is None else period[0]
		period_end = itemList[-1][0] if period[1] is None else period[1]
		# 在长阳以后warmDays内，挨个验证收盘价在20均线之上，且第一个在20均线上下maDiff之间的index
		datetime_list = []
		for index in index_list:
			warmIndexEnd = index+warmDays
			# 处理尾部超出index
			if warmIndexEnd > itemLen:
				warmIndexEnd = itemLen
			# 验证起始位置ma线是否在K线指定位置之下
			indexStart = index
			_close = itemList[index][2]
			_open = itemList[index][1]
			maclose = ma_list[index]
			if maclose > ((_close - _open) * StartMaPos + _open):
				continue
			# 开始验证回落
			for warmIndex in range(indexStart+1, warmIndexEnd):
				close = itemList[warmIndex][2]
				maclose = ma_list[warmIndex]
				macloseLow = maclose * (1.0 - maDiff)
				macloseUp = maclose * (1.0 + maDiff)
				if close <= macloseUp and close >= macloseLow:
					datetime_suite = itemList[warmIndex][0]
					# period鉴别
					if period_start <= datetime_suite and period_end >= datetime_suite:
						datetime_list.append(datetime_suite)
					# 只收第一个
					break
		return datetime_list
		
	# price or vol MA抬头向上(昨<今)
	# subItem=[1,2,3,4,5]代表开收高低量
	def priceVolMaUp(self, itemList, subItem=1, ma_days=10,  period=[None,None]):
		TecIndexObj = TecIndexRecog()
		ma_list = TecIndexObj.MA(itemList, subItem, ma_days)
		datetime_list = []
		if len(ma_list) == 0:
			return []
		period_start = itemList[0][0] if period[0] is None else period[0]
		period_end = itemList[-1][0] if period[1] is None else period[1]
		pre_ma = ma_list[0]
		for cur_ma_i in range(0,len(ma_list)):
			cur_ma = ma_list[cur_ma_i]
			if pre_ma < cur_ma:
				datetime_suite = itemList[cur_ma_i][0]
				if period_start <= datetime_suite and period_end >= datetime_suite:
					datetime_list.append(datetime_suite)
			pre_ma = cur_ma
		return datetime_list

	# 3条均线多头排列
	# ma1 < ma2 < ma3
	def ma3duoTouPaiLie(self, itemList, ma1=5, ma2=10, ma3=20, period=[None,None]):
		TecIndexObj = TecIndexRecog()
		ma1_list = TecIndexObj.MA(itemList, 2, ma1)
		ma2_list = TecIndexObj.MA(itemList, 2, ma2)
		ma3_list = TecIndexObj.MA(itemList, 2, ma3)
		datetime_list = []
		if len(ma3_list) == 0:
			return []
		period_start = itemList[0][0] if period[0] is None else period[0]
		period_end = itemList[-1][0] if period[1] is None else period[1]
		for i in range(0,len(itemList)):
			if ma1_list[i] < ma2_list[i]:
				continue
			if ma2_list[i] < ma3_list[i]:
				continue
			datetime_suite = itemList[i][0]
			if period_start <= datetime_suite and period_end >= datetime_suite:
				datetime_list.append(datetime_suite)
		return datetime_list

	# 收阳，且阳量大于VOLMA10和VOLMA5，且阳量分别大于之前的N天阴量, 且阳线长度3%
	# volma1 < volma2
	def RedAndVolBig(self, itemList, volma1=5, volma2=10, greenDays=3, redLenth=0.03, period=[None,None]):
		TecIndexObj = TecIndexRecog()
		volma1_list = TecIndexObj.MA(itemList, 5, volma1)
		volma2_list = TecIndexObj.MA(itemList, 5, volma2)
		datetime_list = []
		if len(volma2_list) == 0:
			return []
		period_start = itemList[0][0] if period[0] is None else period[0]
		period_end = itemList[-1][0] if period[1] is None else period[1]
		greenVol_deque = deque([])
		for i in range(0,len(itemList)):
			item = itemList[i]
			closePrice = item[2]
			openPrice = item[1]
			vol = item[5]
			if closePrice <= openPrice:
				if len(greenVol_deque) == greenDays:
					greenVol_deque.popleft()
					greenVol_deque.append(vol)
				else:
					greenVol_deque.append(vol)
				continue
			if openPrice == 0.0:
				continue
			if ((closePrice - openPrice) / openPrice) <= redLenth:
				continue
			if vol < volma1_list[i] or vol < volma2_list[i]:
				continue
			if len(greenVol_deque) == 0:
				continue
			if vol < max(greenVol_deque):
				continue
			#if vol < (1.0 * sum(greenVol_deque) / greenDays):
			#	continue
			datetime_suite = item[0]
			if period_start <= datetime_suite and period_end >= datetime_suite:
				datetime_list.append(datetime_suite)
		return datetime_list
				


	# 量价配合指标筛选
	# [indexMin, indexMax]闭闭区间
	def priceVolCoor(self, itemList, item_len, vol_ma_days, indexMin, indexMax, period=[None,None]):
		TecIndexObj = TecIndexRecog()
		valueList = TecIndexObj.priceVolCoordination(itemList, item_len, vol_ma_days)
		if len(valueList) == 0:
			return []
		period_start = itemList[0][0] if period[0] is None else period[0]
		period_end = itemList[-1][0] if period[1] is None else period[1]
		datetime_list = []
		for i in range(0,len(valueList)):
			value = valueList[i]
			if value >= indexMin and value <= indexMax:
				datetime_suite = itemList[i][0]
				if period_start <= datetime_suite and period_end >= datetime_suite:
					datetime_list.append(datetime_suite)
		return datetime_list

	# 红量比例筛选
	# [ratioMin, ratioMax]闭闭区间
	def redGreenRatio(self, itemList, item_len, ratioMin, ratioMax, period=[None,None]):
		TecIndexObj = TecIndexRecog()
		ratio_list = TecIndexObj.redGreenRatio(itemList, item_len)
		if len(ratio_list) == 0:
			return []
		period_start = itemList[0][0] if period[0] is None else period[0]
		period_end = itemList[-1][0] if period[1] is None else period[1]
		datetime_list = []
		for i in range(0,len(ratio_list)):
			ratio = ratio_list[i]
			if ratio >= ratioMin and ratio <= ratioMax:
				datetime_suite = itemList[i][0]
				if period_start <= datetime_suite and period_end >= datetime_suite:
					datetime_list.append(datetime_suite)
		return datetime_list

	# KDJ地位金叉
	def KDJGoldCross(self, itemList, periodN=9, KsmaN=3, DsmaN=3, KDpos=0.2, period=[None,None]):
		TecIndexObj = TecIndexRecog()
		Klist, Dlist = TecIndexObj.KDJ(itemList, periodN, KsmaN, DsmaN)
		if len(itemList) <= 1:
			return []
		period_start = itemList[0][0] if period[0] is None else period[0]
		period_end = itemList[-1][0] if period[1] is None else period[1]
		datetime_list = []
		preK = Klist[0]
		preD = Dlist[0]
		KDposValue = 100.0* KDpos
		for index in range(1, len(itemList)):
			curK = Klist[index]
			curD = Dlist[index]
			if curK > KDposValue or curD > KDposValue:
				preK = curK
				preD = curD
				continue
			if preK < preD and curK > curD:
				datetime = itemList[index][0]
				if period_start <= datetime and period_end >= datetime:
					datetime_list.append(datetime)
			preK = curK
			preD = curD
		return datetime_list



if __name__ == '__main__':
	obj = ExrightsTool()
	flag, itemList = obj.getAdjItemList("600000", "pre", "day", None, None)
	obj = TrendRecog()
	#print obj.pricePos(itemList, historyAll=1, item_len=10, posPercentMin=0.0, posPercentMax=0.2)
	#print obj.pingTai(itemList, item_len=10, volat=0.15, period=[None,None])
	#print obj.warmUpShoot(itemList, 10, 20, 0.07, 0.3, 0.015, 0.5)
	#print obj.priceVolMaUp(itemList, 2, 20)
	#print obj.priceVolCoor(itemList, 5, 5, 0.0, 99.9)
	#print obj.redGreenRatio(itemList, 60, 0.7, 1.0)
	#print obj.KDJGoldCross(itemList, 9, 3, 3)
	#print obj.ma3duoTouPaiLie(itemList)
	print obj.RedAndVolBig(itemList)
